import { isPlainObject } from 'lodash'
import * as path from 'path'
import { ObjectMapper, ObjectMapperStyle } from '@libs/lhy-common'
import { HttpModule, HttpService } from '@nestjs/axios'
import { DynamicModule, Global, Module, ValidationPipe } from '@nestjs/common'
import { APP_FILTER, APP_INTERCEPTOR, APP_PIPE } from '@nestjs/core'
import { ServeStaticModule, ServeStaticModuleOptions } from '@nestjs/serve-static'
import { CoreCacheModule } from './core-cache/core-cache.module'
import {
  AllExceptionFilter,
  CoreExceptionCode,
  CoreHttpException,
  CoreValidationException,
  ParseDatePipe,
  ParseFilePipe,
  ParseImageFilePipe,
  WsExceptionFilter,
} from './core-common'
import { RequestParameterSerializeInterceptor, ResponseParameterSerializeInterceptor } from './core-common/interceptor'
import { CoreConfigService } from './core-config'
import { CoreConfigModule, CoreConfigModuleOption } from './core-config/core-config.module'
import { CoreDatabaseModule } from './core-database'

/**
 * LhyCoreModule 是一个模块类，用于导入 CoreConfigModule。
 */
@Global()
@Module({
  imports: [
    // 静态站映射
    ServeStaticModule.forRootAsync({
      useFactory: (configService: CoreConfigService) =>
        configService.config.statics.map(
          item =>
            ({
              serveRoot: item.urlPrefix,
              rootPath: path.isAbsolute(item.storeRoot) ? item.storeRoot : path.join(__dirname, item.storeRoot),
              serveStaticOptions: {
                setHeaders: (res, path, stat) => {
                  if (/\.(?:html?)$/.test(path)) {
                    // 设置不缓存
                    res.setHeader('Cache-Control', 'private, no-store, no-cache, must-revalidate, proxy-revalidate')
                  } else {
                    // 设置30天缓存
                    res.setHeader('Cache-Control', 'public, max-age=2592000000')
                  }
                },
              },
            }) as ServeStaticModuleOptions
        ),
      inject: [CoreConfigService],
    }),
    // axios配置
    HttpModule.registerAsync({
      useFactory: (configService: CoreConfigService) => ({
        ...configService.config.axios,
      }),
      inject: [CoreConfigService],
    }),
    // 数据库配置
    CoreDatabaseModule,
    // 缓存配置
    CoreCacheModule,
  ],
  providers: [
    // 启用全局校验
    {
      provide: APP_PIPE,
      useValue: new ValidationPipe({
        transform: true,
        whitelist: true,
        exceptionFactory: errors => new CoreValidationException(errors),
      }),
    },
    // 请求参数转驼峰
    {
      provide: APP_INTERCEPTOR,
      useClass: RequestParameterSerializeInterceptor,
    },
    // 响应数据转下划线
    {
      provide: APP_INTERCEPTOR,
      useClass: ResponseParameterSerializeInterceptor,
    },
    // 全局异常过滤器，转为统一格式返回
    {
      provide: APP_FILTER,
      useClass: AllExceptionFilter,
    },
    {
      provide: APP_FILTER,
      useClass: WsExceptionFilter,
    },
    ParseFilePipe,
    ParseImageFilePipe,
    ParseDatePipe,
  ],
  exports: [HttpModule, CoreDatabaseModule, CoreCacheModule, ParseFilePipe, ParseImageFilePipe, ParseDatePipe],
})
export class LhyCoreModule {
  /**
   * 用于全局注册的静态方法
   * @param option - LhyCoreModuleOption 对象，包含模块的配置信息。
   * @returns 返回一个 DynamicModule 对象。
   */
  static forRoot(option: LhyCoreModuleOption): DynamicModule {
    /**
     * configModule 是一个导入 CoreConfigModule 的模块。
     */
    const configModule = CoreConfigModule.forRoot(option.config)

    /**
     * 返回一个 DynamicModule 对象，包含模块的配置信息。
     */
    return {
      global: true,
      module: this,
      imports: [configModule],
      providers: [
        // 重写FilePipe，从配置文件注入初始化配置
        {
          provide: ParseFilePipe,
          useFactory: (configService: CoreConfigService) =>
            new ParseFilePipe({ singleFileSize: configService.config.upload.singleFileSize }),
          inject: [CoreConfigService],
        },
        // 重写ParseImageFilePipe，从配置文件注入初始化配置
        {
          provide: ParseImageFilePipe,
          useFactory: (configService: CoreConfigService) =>
            new ParseImageFilePipe({ singleFileSize: configService.config.upload.singleFileSize }),
          inject: [CoreConfigService],
        },
      ],
      exports: [configModule],
    }
  }

  constructor(private httpService: HttpService) {
    this.initAxios()
  }

  /**
   * 初始化Axios配置
   */
  protected initAxios() {
    this.httpService.axiosRef.interceptors.response.use(
      response => {
        if (response.status >= 200 && response.status < 300 && isPlainObject(response.data)) {
          response.data = ObjectMapper.mapObject(response.data, ObjectMapperStyle.CamelCase)
        }
        return response
      },
      err => {
        if (err.code === CoreExceptionCode.Prompt) {
          return Promise.reject(new CoreHttpException(err.message, { code: CoreExceptionCode.Prompt }))
        }
        return Promise.reject(err)
      }
    )
  }
}

/**
 * 配置项
 */
export interface LhyCoreModuleOption {
  /**
   * config 是 CoreConfigModuleOption 对象，用于配置 CoreConfigModule。
   */
  config?: CoreConfigModuleOption
}
